package org.ytor.common.util.invoke;

import org.ytor.common.classmeta.ConstructorMetadata;
import org.ytor.common.util.cache.ClassCache;
import org.ytor.common.util.invoke.support.ReflectInvoke;

import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.Map;

/**
 * created by yangtong on 2025/4/8 16:06:36
 * <br/>
 * 反射工具类
 */
public class Reflects {

    static Invoke invoke = new ReflectInvoke();

    //基本类型和包装类型映射
    private static final Map<Class<?>, Class<?>> PRIMITIVE_TO_WRAPPER = Map.of(
            boolean.class, Boolean.class,
            byte.class, Byte.class,
            char.class, Character.class,
            short.class, Short.class,
            int.class, Integer.class,
            long.class, Long.class,
            float.class, Float.class,
            double.class, Double.class,
            void.class, Void.class
    );

    /**
     * 根据class实例化对象
     */
    public static <T> T newInstance(Class<T> clazz, Object... args) throws InvocationTargetException, InstantiationException, IllegalAccessException {
        ConstructorMetadata<T> constructor = ClassCache.getConstructor(clazz, argsToClasses(args));
        return constructor.instance(args);
    }

    /**
     * 获取对象的字段
     */
    public static <T> Object getFieldValue(T target, String fieldName) throws InvocationTargetException, IllegalAccessException {
        return invoke.getFieldValue(target, fieldName);
    }

    /**
     * 获设置对象的字段值
     */
    public static <T> void setFieldValue(T target, String fieldName, Object value) throws InvocationTargetException, IllegalAccessException {
        invoke.setFieldValue(target, fieldName, value);
    }

    /**
     * 调用对象的方法
     */
    public static <T> Object invokeMethod(T target, String methodName, Class<?>[] paramTypes, Object... args) throws InvocationTargetException, IllegalAccessException {
        return invoke.invokeMethod(target, methodName, paramTypes, args);
    }

    /**
     * 调用对象的方法
     */
    public static <T> Object invokeMethod(T target, String methodName, Object... args) throws InvocationTargetException, IllegalAccessException {
        return invokeMethod(target, methodName, argsToClasses(args), args);
    }

    public static Class<?>[] argsToClasses(Object... args) {
        if (args == null) {
            return new Class<?>[]{Object.class};
        }
        Class<?>[] types = new Class<?>[args.length];
        for (int i = 0; i < args.length; i++) {
            Object arg = args[i];
            if (arg == null) {
                types[i] = Object.class;
            } else {
                types[i] = args[i].getClass();
            }
        }
        return types;
    }

    /**
     * 基本类型转包装类型
     */
    public static Class<?> primitiveToWrapper(Class<?> clazz) {
        return clazz.isPrimitive() ? PRIMITIVE_TO_WRAPPER.get(clazz) : clazz;
    }

}
